﻿#region << 版 本 注 释 >>

/*----------------------------------------------------------------
* 类 名 称 ：State
* 类 描 述 ：
* 作    者 ：henrychang
* 创建时间 ：2019/1/27 23:48:28
*******************************************************************
* Copyright @ henrychang 2019. All rights reserved.
*******************************************************************
//----------------------------------------------------------------*/

#endregion << 版 本 注 释 >>

using System;
using System.Collections.Generic;
using TouchFish.Event;
using TouchFish.ToolClass;

namespace TouchFish.StateMachine
{
    /// <summary>
    /// 状态机状态基类
    /// </summary>
    /// <typeparam name="T">状态机持有者类型</typeparam>
    public abstract class State<T> where T : class
    {
        private readonly MessageSystem _messageSystem;

        /// <summary>
        /// 初始化状态机状态基类的新实例
        /// </summary>
        public State()
        {
            _messageSystem = new MessageSystem();
        }

        /// <summary>
        /// 状态机状态初始化时调用
        /// </summary>
        /// <param name="fsm">有限状态机引用。</param>
        protected internal virtual void OnInit(IStateMachine<T> fsm)
        {
        }

        /// <summary>
        /// 状态机状态进入时调用
        /// </summary>
        /// <param name="fsm">状态机引用</param>
        protected internal virtual void OnEnter(IStateMachine<T> fsm)
        {
        }

        /// <summary>
        /// 状态机状态轮询时调用
        /// </summary>
        /// <param name="fsm">状态机引用</param>
        protected internal virtual void OnUpdate(IStateMachine<T> fsm)
        {
        }

        /// <summary>
        /// 状态机状态离开时调用
        /// </summary>
        /// <param name="fsm">状态机引用。</param>
        /// <param name="isShutdown">是否是关闭有限状态机时触发。</param>
        protected internal virtual void OnLeave(IStateMachine<T> fsm)
        {
        }

        /// <summary>
        /// 状态机状态销毁时调用
        /// </summary>
        /// <param name="fsm">状态机引用</param>
        protected internal virtual void OnDestroy(IStateMachine<T> fsm)
        {
            _messageSystem.OnRecycled();
        }

        /// <summary>
        /// 注册状态机事件
        /// </summary>
        /// <param name="eventId">事件编号</param>
        /// <param name="eventHandler">状态机事件响应函数</param>
        protected void RegisterMessage(int eventId, OnEvent func)
        {
            _messageSystem.RegisterMessage(eventId, func);
        }

        /// <summary>
        /// 取消注册状态机事件
        /// </summary>
        /// <param name="eventId">事件编号</param>
        /// <param name="eventHandler">状态机事件响应函数</param>
        protected void UnRegisterMessage(int eventId, OnEvent func)
        {
            _messageSystem.UnRegisterMessage(eventId, func);
        }

        /// <summary>
        /// 切换当前状态机状态
        /// </summary>
        /// <typeparam name="TState">要切换到的状态机状态类型</typeparam>
        /// <param name="fsm">有限状态机引用</param>
        protected void ChangeState<TState>(IStateMachine<T> fsm) where TState : State<T>
        {
            StateMachine<T> fsmImplement = (StateMachine<T>)fsm;
            if (fsmImplement == null)
            {
                throw new Exception("FSM is invalid.");
            }

            fsmImplement.ChangeState<TState>();
        }

        /// <summary>
        /// 切换当前状态机状态
        /// </summary>
        /// <param name="fsm">状态机引用</param>
        /// <param name="stateType">要切换到的状态机状态类型</param>
        protected void ChangeState(IStateMachine<T> fsm, Type stateType)
        {
            StateMachine<T> fsmImplement = (StateMachine<T>)fsm;
            if (fsmImplement == null)
            {
                throw new Exception("FSM is invalid.");
            }

            if (stateType == null)
            {
                throw new Exception("State type is invalid.");
            }

            if (!typeof(State<T>).IsAssignableFrom(stateType))
            {
                throw new Exception(StringUtil.Format("State type '{0}' is invalid.", stateType.FullName));
            }

            fsmImplement.ChangeState(stateType);
        }

        /// <summary>
        /// 响应状态机事件时调用
        /// </summary>
        /// <param name="eventId">事件编号</param>
        /// <param name="param">事件参数</param>
        internal void OnEvent(int eventId, params object[] param)
        {
            _messageSystem.SendMessage(eventId, param);
        }
    }
}